<?php
	/**
	 * Handles data to save.
	 * @author IMP
	 */
	
	class DataDirectory extends Dir {		
		public function __construct($name){
			if(preg_match('#^([a-z0-9_\-\!\+]+)$#i', $name)){
				$path = PATH_DATA . DS . $name;
				parent::__construct($path, true, 0700);
			}else{
				throw new Exception('Name may only consist of a-Z, 0-9, _, -, ! and +.');
			}
		}
		
		public function store($name, Resource $r){
			$classFileName = $this->getAbsolutePath($name . '.class');
			$name = call_user_func(array(get_class($r), 'formFilename'), $name);
			$file = new File($this->getAbsolutePath($name), true);
			
			if($this->contains($file)){
				$classFile = new File($classFileName, true);
				$r->save($file);
				$classFile->write(get_class($r));
			}else throw new Exception('Invalid path ' . $file . '.');
		}
		
		public function containsResource($name){
			return $this->contains(new File($this->getAbsolutePath($name . '.class')));
		}
		
		public function listResources($pattern, $type = null){
			$classesa = $this->search($pattern . '.class');
			$classes = array();
			
			foreach($classesa as $c){
				$resourceFileName = $this->getRelativePath($c);
				$resource = substr($resourceFileName, 0, strlen($resourceFileName) - 6);
				$classFile = new File($c);
				$class = $classFile->read();
				
				if(class_exists($class, true) && ($type == $class || is_subclass_of($class, $type) || in_array($type, class_implements($class, true)) || $type == null)) $classes[$resource] = $class;
			}
			
			return $classes;
		}
		
		public function restore($name){
			$classFileName = $this->getAbsolutePath($name . '.class');
			if(File::exists($classFileName)){
				$classFile = new File($classFileName);
				$class = $classFile->read();
				
				if(class_exists($class, true) && in_array('Resource', class_implements($class, true))){
					$name = call_user_func(array($class, 'formFilename'), $name);
					$file = new File($this->getAbsolutePath($name));
					if($this->contains($file)){
						$r = call_user_func(array($class, 'open'), $file);
						if($r instanceof Resource && $r instanceof $class){
							return $r;
						}else{
							throw new Exception('Resource::open has to return an object that inherits Resource and ' . $class . '.');
						}
					}else throw new Exception('Invalid name.');
				}else{
					throw new Exception('Class ' . $class . ' (' .  implode(', ', class_implements($class, true)) . ') is invalid.');
				}
			}else{
				throw new Exception('Resource ' . $name . ' does not exist.');
			}
		}
		
		private static function captureAllDirs(Dir $d){
			$dirs = array();
			foreach($d->listDirectories() as $d2){
				$dirs[] = $d2;
				$dirs = array_merge($dirs, self::captureAllDirs($d2));
			}
			
			return $dirs;
		}
		
		public function pack(File $output){
			$zip = new ZipArchive();
			$r = $zip->open($output, ZipArchive::CREATE);
			
			if($r === true){
				foreach(self::captureAllDirs($this) as $d){
					$zip->addEmptyDir($this->getRelativePath($d));
					foreach($d->listFiles() as $f){
						$zip->addFile($f, $this->getRelativePath($f));
					}
				}
				
				foreach($this->listFiles() as $f){
					$zip->addFile($f, $this->getRelativePath($f));
				}
				
				$zip->close();
			}else{
				throw new Exception('Failed to open archive, error code: ' . $r . '.');
			}
		}
		
		public function unpack(ZipArchive $a){
			$a->extractTo($this);
		}
	}
?>